package thinkinginjava.concurrency;

import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

public class Memoizer3<K, V> implements Computable<K, V>{
	private final Map<K, Future<V>> cache = new ConcurrentHashMap<K, Future<V>>();
	private final Computable<K, V> c;
	
	
	public Memoizer3(Computable<K, V> c) {
		super();
		this.c = c;
	}


	@Override
	public V compute(final K arg) throws InterruptedException {
		Future<V> f = cache.get(arg);
		if(f == null) {
			Callable<V> eval = new Callable<V>() {
				@Override
				public V call() throws Exception {
					return c.compute(arg);
				}
			};
			FutureTask<V> ft = new FutureTask<V>(eval);
			f = ft;
			cache.put(arg, f);
			ft.run();
		}
		try {
			return f.get();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

}
